home *** CD-ROM | disk | FTP | other *** search
/ BBS in a Box 4 / BBS in a Box - Macintosh - Volume IV (January 1992) (BBS in a Box).iso / Files / Prog / U-Z / Vax Storage < prev    next >
Encoding:
Text File  |  1987-11-28  |  3.5 KB  |  98 lines  |  [TEXT/MACA]

  1. This Pascal fragment illustrates how to calculate an XMODEM/YMODEM 
  2. type Cyclic Redundancy Check (CRC) with minimal performance overhead, 
  3. namely on a one-operation-per-byte basis.  It is nearly as fast as 
  4. the old arithmetic checksum.  Communications programmers who don't 
  5. know the "256 word table" trick will want to download this file so
  6. they can improve their code's performance.  Also curiosity-seekers 
  7. and for general education.
  8.  
  9. A SHORT HISTORY
  10.  
  11. The contributor has recently (11/25/87) written an XMODEM/YMODEM 
  12. program in VAX Pascal.  I planned to use the VAX CRC instruction
  13. but discovered it computed CRC's with the least-significant-bit of 
  14. each byte going in first, while the XMODEM/YMODEM CRC wants the 
  15. most-significant bit to be inserted first.  The table-driven 
  16. nature of the VAX instruction, and dissatisfaction with the overhead 
  17. of bitwise computation, led me to discover the algorithm shown here.
  18.  
  19. This has been tested by using an incorrect polynomial, which of course 
  20. leads to a hard error.  It has NOT been tested by injection of line 
  21. errors (direct link used on the system on which it was developed, and 
  22. no electriv drill handy).  It is free and public domain.  
  23.  
  24. { some type declarations to keep VAX Pascal happy.}
  25.  
  26. TYPE $UBYTE = [BYTE]0..255;  $UWORD = [WORD]0..65535;
  27.  
  28. {the following type aCRC is dependent on VAX storage allocation, 
  29.  and will be different on othe machines, particularly 16-bit ones.}
  30.  
  31.   aCRC = PACKED RECORD CASE INTEGER OF
  32.     1: (crc32 : UNSIGNED);
  33.     2: (crc16,hi16 : $UWORD);
  34.     3: (lsbyte,nlsbyte,nmsbyte,msbyte : $UBYTE);
  35.   END;
  36.  
  37. VAR crcTab : ARRAY [0..255] OF $UWORD; {global var, 16-bit entries}
  38.  
  39.  
  40. FUNCTION CRC(Buffer:PACKED ARRAY [1..1026] OF CHAR; Cnt:INTEGER):$UWORD;
  41.  
  42. {this function computes and returns the 16-bit CRC of the first (Cnt)
  43.   bytes in Buffer.  For XMODEM/YMODEM transmission, it would be called 
  44.   with Cnt=128 or 1024.  For reception, it would be called with Cnt=
  45.   130 or 1026.  (Including the CRC itself in the calculation should 
  46.   "cancel" the accumulation up to that point, and the returned value 
  47.   is 0 if all is well.)  The SOH/STX and the two record number bytes 
  48.   are not included in the CRC, and it's assumed they went somewhere 
  49.   else than in Buffer.
  50.   
  51.   UXOR is a VAX Pascal function that does a 32-bit Exclusive OR 
  52.       and returns an "unsigned" value.
  53.   UINT is a VAX Pascal type transfer function that returns "UNSIGNED".
  54.   ORD is a Pascal type transfer function that returns "INTEGER"
  55.   
  56.   In other words, UINT and ORD don't do anything useful...
  57.   }
  58. VAR i:INTEGER; compCRC:aCRC; 
  59. BEGIN
  60.     WITH compCRC DO BEGIN
  61.  
  62.     crc32:=0;
  63.     
  64.     FOR i:=1 to Cnt DO crc32:=
  65.     UXOR( lsbyte*256, crcTab[ ORD( UXOR( nlsbyte, UINT( Buffer[i])))]);
  66.  
  67.     CRC:=crc16;
  68.     END {WITH};
  69. END;
  70.  
  71. {in plainer terms: for each byte in Buffer, we compute a new 16-bit 
  72. CRC as
  73.  
  74. new CRC:=(oldCRC lo byte shifted left 8 bits, with 0's coming in)
  75.       XOR
  76.      crcTab[ (old CRC hi byte) XOR (the byte from Buffer) ]
  77.      
  78. where the contents of crcTab are computed at program startup by the 
  79. following subroutine:
  80. }
  81.  
  82.  
  83. PROCEDURE initCRCTab;
  84. VAR theCRC: aCRC; i,j:INTEGER;
  85. BEGIN
  86.     WITH theCRC DO 
  87.     FOR i:=0 TO 255 DO BEGIN        {fill up the table}
  88.     crc32:=i*256;             {index value shifted 8 right}
  89.     FOR j:=1 to 8 DO BEGIN      {test each of the 8 hi bits}
  90.         crc32:=crc32+crc32;     {left shift all 16 by 1}
  91.         IF hi16>0 THEN         {and if the bit shifted out is 1}
  92.         crc32:= UXOR(crc16,%X'1021'); {then XOR in the polynomial}
  93.     END {FOR j};            {for all 8}
  94.     crcTab[i]:=crc16;        {put the result in the table}
  95.     END {FOR i};
  96. END;